/*
 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.nio.channels;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.spi.AbstractInterruptibleChannel;
import java.nio.file.*;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.spi.*;
import java.util.Set;
import java.util.HashSet;
import java.util.Collections;

/**
 * 用于读取、写入、映射和操作文件的通道。
 *
 * <p> 文件通道是连接到文件的可查找字节通道。
 * 它在文件中有一个当前位置，可以查询和修改。
 * 文件本身包含一个可变长度的字节序列，这些字节可以读写，并且可以查询其当前大小。
 * 当写入的字节超过当前大小时，文件的大小会增加；
 * 当文件被截断时，文件的大小会减小。
 * 该文件还可能有一些相关的元数据，如访问权限、内容类型和上次修改时间；
 * 此类不定义元数据访问的方法。
 *
 * <p> 除了类似的字节通道的读、写和关闭操作外，此类还定义了以下特定于文件的操作：</p>
 *
 * <ul>
 *
 *   <li><p> 可以在文件的绝对位置以不影响信道当前位置的方式
 *   读取read(ByteBuffer, long)或写入write(ByteBuffer, long)字节。</p></li>
 *
 *   <li><p> 文件的一个区域可以直接映射到内存中；
 *   对于大文件，这通常比调用通常的读或写方法更有效。
 *   </p></li>
 *
 *   <li><p> 对文件所做的更新可以强制到底层存储设备，以确保在系统崩溃时数据不会丢失。</p></li>
 *
 *   <li><p> 字节可以从一个文件传输到另一个通道，
 *   并且可以通过许多操作系统优化的方式，直接传输到文件系统缓存或直接从文件系统缓存传输。
 *   </p></li>
 *
 *   <li><p> 文件的一个区域可能被锁定，不允许其他程序访问。  </p></li>
 *
 * </ul>
 *
 * <p> 多个并发线程可以安全地使用文件通道。
 * close方法可以在任何时候调用，正如Channel接口指定的那样。
 * 在任何给定的时间内，只有一个涉及通道位置或可以更改其文件大小的操作正在进行；
 * 尝试启动第二个此类操作，而正在进行的第一个操作，第二个操作将被阻止，直到第一个操作完成。
 * 其他操作，特别是那些采取明确position的操作，可能同时进行；
 * 它们是否真的这样做取决于底层实现，因此未作说明。
 *
 * <p> 此类实例提供的文件视图被保证与同一程序中其他实例提供的同一文件的其他视图一致。
 * 但是，由于底层操作系统执行的缓存和网络文件系统协议引起的延迟，
 * 此类实例提供的视图可能与其他并发运行的程序所看到的视图一致，也可能不一致。
 * 不管这些程序是用什么语言编写的，也不管它们是在同一台机器上运行还是在其他机器上运行，这都是正确的。
 * 任何此类不一致的确切性质都是系统依赖性的，因此未指定。
 *
 * <p> 文件通道是通过调用这个类定义的一个open方法来创建的。
 * 还可以通过调用该对象的getChannel方法从现有的FileInputStream、
 * FileOutputStream或RandomAccessFile对象获取文件通道，该方法返回连接到同一基础文件的文件通道。
 * 如果文件通道是从现有的流或随机访问文件获得的，那么文件通道的状态与getChannel方法返回通道的对象的状态密切相关。
 * 改变通道的位置，无论是显式的还是读写字节的，都会改变原始对象的文件位置，反之亦然。
 * 通过文件通道更改文件的长度将更改通过原始对象看到的长度，反之亦然。
 * 通过写入字节来更改文件的内容将更改原始对象看到的内容，反之亦然。
 *
 * <a name="open-mode"></a> <p> 
 * 在不同的时候，这个类指定需要一个“为读取打开”、“为写入打开”或“为读写打开”的实例。
 * 通过java.io.FileInputStream的getChannel方法获得的通道,可以进行读取。
 * 通过java.io.FileOutputStream的getChannel方法获得的信道，可以进行写入。
 * 最后，通过java.io.RandomAccessFile的getChannel方法获得的通道，
 * 如果实例创建模式为“r”，可以进行读取，
 * 如果实例创建模式为“rw”，可以进行读取和写入，。
 *
 * <a name="append-mode"></a><p> 为写入而打开的文件通道可能处于追加模式，
 * 例如，如果它是从通过调用FileOutputStream(file,boolean)构造函数并为第二个参数传递true创建的FileOutputStream中获得的。
 * 在这种模式下，每次相对写操作的调用首先将位置推进到文件的末尾，然后写入所请求的数据。
 * 位置的提升和数据的写入是否在单个原子操作中完成是系统依赖的，因此未指定。
 *
 * @see java.io.FileInputStream#getChannel()
 * @see java.io.FileOutputStream#getChannel()
 * @see java.io.RandomAccessFile#getChannel()
 *
 * @author Mark Reinhold
 * @author Mike McCloskey
 * @author JSR-51 Expert Group
 * @since 1.4
 */

public abstract class FileChannel
    extends AbstractInterruptibleChannel
    implements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel
{
    /**
     * Initializes a new instance of this class.
     */
    protected FileChannel() { }

    /**
     * 打开或创建一个文件，返回访问该文件的文件通道。
     *
     * <p> options参数决定如何打开文件。
     * StandardOpenOption.READ和WRITE选项决定是否应该打开文件进行读写。
     * 如果数组中不包含任何选项(或APPEND选项)，则打开文件进行读取。
     * 默认情况下，读取或写入从文件的开头开始。
     *
     * <p> 除了读和写之外，可能还会出现以下选项:
     *
     * <table border=1 cellpadding=5 summary="">
     * <tr> <th>Option</th> <th>Description</th> </tr>
     * <tr>
     *   <td> {@link StandardOpenOption#APPEND APPEND} </td>
     *   <td> 如果存在此选项，则打开文件进行写操作，每次调用通道的write方法都会先将该位置移到文件的末尾，然后写入需要的数据。
     *     位置的提升和数据的写入是否在单个原子操作中完成是系统相关的，因此未指定。
     *     此选项不能与READ或TRUNCATE_EXISTING选项联合使用。</td>
     * </tr>
     * <tr>
     *   <td> {@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING} </td>
     *   <td> 如果存在此选项，则现有文件将被截断为0字节的大小。
     *   当只打开文件供阅读时，此选项将被忽略。</td>
     * </tr>
     * <tr>
     *   <td> {@link StandardOpenOption#CREATE_NEW CREATE_NEW} </td>
     *   <td> 如果存在此选项，则创建一个新文件，如果文件已经存在则失败。
     *   当创建一个文件时，检查该文件是否存在，如果该文件不存在，则创建该文件，
     *   文件是否存在的检查和文件不存在时的创建相对于其他文件系统操作来说是原子的。
     *   当只打开文件供阅读时，此选项将被忽略。</td>
     * </tr>
     * <tr>
     *   <td > {@link StandardOpenOption#CREATE CREATE} </td>
     *   <td> 如果存在此选项，则打开现有文件(如果存在)，否则创建一个新文件。
     *   当创建一个文件时，文件是否存在的检查和文件不存在时的创建相对于其他文件系统操作来说是原子的。
     *   如果还存在CREATE_NEW选项，或者文件只打开用于读取，则忽略该选项。</td>
     * </tr>
     * <tr>
     *   <td > {@link StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} </td>
     *   <td> 当此选项存在时，实现将尽最大努力，在close方法关闭时，删除文件。
     *   如果close方法没有被调用，那么当Java虚拟机终止时，将尽力删除文件。</td>
     * </tr>
     * <tr>
     *   <td>{@link StandardOpenOption#SPARSE SPARSE} </td>
     *   <td> 当创建一个新文件时，此选项是一个提示，新文件将是稀少的。
     *   当不创建新文件时将忽略此选项。</td>
     * </tr>
     * <tr>
     *   <td> {@link StandardOpenOption#SYNC SYNC} </td>
     *   <td> 要求对文件内容或元数据的每次更新都同步地写入底层存储设备。
     *   (请参阅同步I/O文件完整性)。</td>
     * </tr>
     * <tr>
     *   <td> {@link StandardOpenOption#DSYNC DSYNC} </td>
     *   <td> 要求对文件内容的每次更新都同步地写入底层存储设备。
     *   (请参阅同步I/O文件完整性)。</td>
     * </tr>
     * </table>
     *
     * <p> 实现还可能支持其他选项。
     *
     * <p>  attrs参数是一个可选的FileAttribute数组，FileAttribute是在创建文件时自动设置的。
     *
     * <p> 通过调用创建Path的提供程序FileSystemProvider的newFileChannel方法来创建新通道。
     *
     * @param   path
     *          The path of the file to open or create
     * @param   options
     *          Options specifying how the file is opened
     * @param   attrs
     *          An optional list of file attributes to set atomically when
     *          creating the file
     *
     * @return  A new file channel
     *
     * @throws  IllegalArgumentException
     *          If the set contains an invalid combination of options
     * @throws  UnsupportedOperationException
     *          If the {@code path} is associated with a provider that does not
     *          support creating file channels, or an unsupported open option is
     *          specified, or the array contains an attribute that cannot be set
     *          atomically when creating the file
     * @throws  IOException
     *          If an I/O error occurs
     * @throws  SecurityException
     *          If a security manager is installed and it denies an
     *          unspecified permission required by the implementation.
     *          In the case of the default provider, the {@link
     *          SecurityManager#checkRead(String)} method is invoked to check
     *          read access if the file is opened for reading. The {@link
     *          SecurityManager#checkWrite(String)} method is invoked to check
     *          write access if the file is opened for writing
     *
     * @since   1.7
     */
    public static FileChannel open(Path path,
                                   Set<? extends OpenOption> options,
                                   FileAttribute<?>... attrs)
        throws IOException
    {
        FileSystemProvider provider = path.getFileSystem().provider();
        return provider.newFileChannel(path, options, attrs);
    }

    @SuppressWarnings({"unchecked", "rawtypes"}) // generic array construction
    private static final FileAttribute<?>[] NO_ATTRIBUTES = new FileAttribute[0];

    /**
     * 打开或创建一个文件，返回访问该文件的文件通道。
     *
     * <p> 此方法的调用行为与调用的方式完全相同
     * <pre>
     *     fc.{@link #open(Path,Set,FileAttribute[]) open}(file, opts, new FileAttribute&lt;?&gt;[0]);
     * </pre>
     * 其中opts是选项数组中指定的一组选项。
     *
     * @param   path
     *          The path of the file to open or create
     * @param   options
     *          Options specifying how the file is opened
     *
     * @return  A new file channel
     *
     * @throws  IllegalArgumentException
     *          If the set contains an invalid combination of options
     * @throws  UnsupportedOperationException
     *          If the {@code path} is associated with a provider that does not
     *          support creating file channels, or an unsupported open option is
     *          specified
     * @throws  IOException
     *          If an I/O error occurs
     * @throws  SecurityException
     *          If a security manager is installed and it denies an
     *          unspecified permission required by the implementation.
     *          In the case of the default provider, the {@link
     *          SecurityManager#checkRead(String)} method is invoked to check
     *          read access if the file is opened for reading. The {@link
     *          SecurityManager#checkWrite(String)} method is invoked to check
     *          write access if the file is opened for writing
     *
     * @since   1.7
     */
    public static FileChannel open(Path path, OpenOption... options)
        throws IOException
    {
        Set<OpenOption> set = new HashSet<OpenOption>(options.length);
        Collections.addAll(set, options);
        return open(path, set, NO_ATTRIBUTES);
    }

    // -- Channel operations --

    /**
     * 从这个通道读取字节序列到给定的缓冲区。
     *
     * <p> 字节从该通道的当前文件位置开始读取，然后文件位置根据实际读取的字节数更新。
     * 否则，此方法的行为与ReadableByteChannel接口中指定的完全一样。</p>
     */
    public abstract int read(ByteBuffer dst) throws IOException;

    /**
     * 从这个通道读取字节序列到给定缓冲区的子序列。
     *
     * <p> 字节从该通道的当前文件位置开始读取，然后文件位置根据实际读取的字节数更新。
     *  否则，此方法的行为与ScatteringByteChannel接口中指定的完全一样。</p>
     */
    public abstract long read(ByteBuffer[] dsts, int offset, int length)
        throws IOException;

    /**
     * 从这个通道读取字节序列到给定的缓冲区。
     *
     * <p> 字节从该通道的当前文件位置开始读取，然后文件位置根据实际读取的字节数更新。
     * 否则，此方法的行为与ScatteringByteChannel接口中指定的完全一样。</p>
     */
    public final long read(ByteBuffer[] dsts) throws IOException {
        return read(dsts, 0, dsts.length);
    }

    /**
     * 将一个字节序列从给定的缓冲区写入此通道。
     *
     * <p> 字节从通道的当前文件位置开始写入，除非通道处于追加模式，在这种情况下，位置首先被推进到文件的末尾。
     * 如果有必要，文件会增长以容纳写入的字节，然后根据实际写入的字节数更新文件位置。
     * 否则，这个方法的行为与WritableByteChannel接口指定的完全一样。</p>
     */
    public abstract int write(ByteBuffer src) throws IOException;

    /**
     * 从给定缓冲区的子序列向该通道写入字节序列。
     *
     * <p> 字节从通道的当前文件位置开始写入，除非通道处于追加模式，在这种情况下，位置首先被推进到文件的末尾。
     * 如果有必要，文件会增长以容纳写入的字节，然后根据实际写入的字节数更新文件位置。
     * 否则，该方法的行为与在GatheringByteChannelinterface中指定的完全一样。</p>
     */
    public abstract long write(ByteBuffer[] srcs, int offset, int length)
        throws IOException;

    /**
     * 从给定缓冲区向该通道写入字节序列。
     *
     * <p> 字节从通道的当前文件位置开始写入，除非通道处于追加模式，在这种情况下，位置首先被推进到文件的末尾。
     * 如果有必要，文件会增长以容纳写入的字节，然后根据实际写入的字节数更新文件位置。
     * 否则，该方法的行为与在GatheringByteChannelinterface中指定的完全一样。</p>
     */
    public final long write(ByteBuffer[] srcs) throws IOException {
        return write(srcs, 0, srcs.length);
    }


    // -- Other operations --

    /**
     * 返回通道的文件位置
     *
     * @return  This channel's file position,
     *          a non-negative integer counting the number of bytes
     *          from the beginning of the file to the current position
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract long position() throws IOException;

    /**
     * 设置该通道的文件位置。
     *
     * <p> 将位置设置为大于文件当前大小的值是合法的，但不会改变文件的大小。
     * 稍后尝试在这个位置，读取字节将立即返回文件结束指示。
     * 以后在这种位置写入字节的尝试将导致文件增长以容纳新字节;
     * 前一个文件结束字节和新写入字节之间的任何字节的值都是未指定的。</p>
     *
     * @param  newPosition
     *         The new position, a non-negative integer counting
     *         the number of bytes from the beginning of the file
     *
     * @return  This file channel
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  IllegalArgumentException
     *          If the new position is negative
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract FileChannel position(long newPosition) throws IOException;

    /**
     * 返回这个通道的文件的当前大小
     *
     * @return  The current size of this channel's file,
     *          measured in bytes
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract long size() throws IOException;

    /**
     * 将此通道的文件截断为给定的大小。
     *
     * <p> 如果给定的大小小于文件的当前大小，那么文件将被截断，丢弃文件新结束以外的任何字节。
     * 如果给定的大小大于或等于文件的当前大小，则文件不会被修改。
     * 在任何一种情况下，如果该通道的文件位置大于给定的大小，那么它就被设置为该大小。
     * </p>
     *
     * @param  size
     *         The new size, a non-negative byte count
     *
     * @return  This file channel
     *
     * @throws  NonWritableChannelException
     *          If this channel was not opened for writing
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  IllegalArgumentException
     *          If the new size is negative
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract FileChannel truncate(long size) throws IOException;

    /**
     * 强制将此通道文件的任何更新写入包含它的存储设备。
     *
     * <p> 如果此通道的文件驻留在本地存储设备上，那么当此方法返回时，
     * 可以保证创建了此通道以来的文件，或者自上次调用此方法以来，对文件所做的所有更改都已写入该设备。
     * 这对于确保在系统崩溃时不丢失关键信息非常有用。
     *
     * <p> 如果文件不在本地设备上，则不做这样的保证。
     *
     * <p> metaData参数可用于限制此方法需要执行的I/O操作的数量。
     * 为该参数传递false表示只有对文件内容的更新才需要写入存储器;
     * 传递true表示对文件内容和元数据的更新都必须写入，这通常需要至少一次I/O操作。
     * 这个参数是否真的有影响取决于底层操作系统，因此未指定。
     *
     * <p> 调用此方法可能导致I/O操作发生，即使通道仅为读取而打开。
     * 例如，一些操作系统维护最后访问时间作为文件元数据的一部分，并且每当读取文件时这段时间都会更新。
     * 是否真的这样做是系统依赖的，因此是未指定的。
     *
     * <p> 此方法只能保证强制通过该类中定义的方法对该通道的文件进行更改。
     * 它可能强制也可能不强制，通过修改，通过调用map方法获得的MappedByteBuffer的内容，而进行的更改。
     * 调用映射字节缓冲区的force方法将强制写入对缓冲区内容所做的更改。</p>
     *
     * @param   metaData
     *          If <tt>true</tt> then this method is required to force changes
     *          to both the file's content and metadata to be written to
     *          storage; otherwise, it need only force content changes to be
     *          written
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract void force(boolean metaData) throws IOException;

    /**
     * 从这个通道的文件传输字节到给定的可写字节通道。
     *
     * <p> 尝试从该通道文件中的给定位置开始读取最多count字节，并将它们写入目标通道。
     * 调用此方法可以或不可以传递所有请求的字节;它是否这样做取决于性质和状态的渠道。
     * 如果此通道的文件从给定位置开始包含的字节数少于count字节，或者如果目标通道是非阻塞的，
     * 并且它的输出缓冲区中空闲的字节数少于count字节，则传输的字节数少于请求的字节数。
     *
     * <p> 此方法不修改该通道的位置。如果给定的位置大于文件的当前大小，则不传输字节。
     * 如果目标通道有一个位置，那么从这个位置开始写入字节，然后这个位置增加写入的字节数。
     *
     * <p> 这种方法可能比简单的循环(从这个通道读取并写入目标通道)高效得多。
     * 许多操作系统可以直接将字节从文件系统缓存传输到目标通道，而不需要实际复制它们。</p>
     *
     * @param  position
     *         The position within the file at which the transfer is to begin;
     *         must be non-negative
     *
     * @param  count
     *         The maximum number of bytes to be transferred; must be
     *         non-negative
     *
     * @param  target
     *         The target channel
     *
     * @return  The number of bytes, possibly zero,
     *          that were actually transferred
     *
     * @throws IllegalArgumentException
     *         If the preconditions on the parameters do not hold
     *
     * @throws  NonReadableChannelException
     *          If this channel was not opened for reading
     *
     * @throws  NonWritableChannelException
     *          If the target channel was not opened for writing
     *
     * @throws  ClosedChannelException
     *          If either this channel or the target channel is closed
     *
     * @throws  AsynchronousCloseException
     *          If another thread closes either channel
     *          while the transfer is in progress
     *
     * @throws  ClosedByInterruptException
     *          If another thread interrupts the current thread while the
     *          transfer is in progress, thereby closing both channels and
     *          setting the current thread's interrupt status
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract long transferTo(long position, long count,
                                    WritableByteChannel target)
        throws IOException;

    /**
     * 将字节从给定的可读通道传输到此通道的文件中。
     *
     * <p> 尝试从源通道读取字节数，并从给定位置开始将它们写入该通道的文件。
     * 调用此方法可以或不可以传输所有请求的字节;
     * 它是否会这样做，取决于渠道的性质和状态。
     * 如果源通道剩余的字节数小于count，或者源通道是非阻塞的，
     * 并且在它的输入缓冲区中立即可用的字节数小于count，那么将被传输的字节数小于请求的字节数。
     *
     * <p> 此方法不修改该通道的位置。
     * 如果给定的位置大于文件的当前大小，则不传输字节。
     * 如果源通道有一个位置，那么字节将从这个位置开始读取，然后这个位置将增加读取的字节数。
     *
     * <p> 这种方法可能比从源通道读取并写入该通道的简单循环更有效。
     * 许多操作系统可以直接将字节从源通道传输到文件系统缓存中，而不需要实际复制它们。</p>
     *
     * @param  src
     *         The source channel
     *
     * @param  position
     *         The position within the file at which the transfer is to begin;
     *         must be non-negative
     *
     * @param  count
     *         The maximum number of bytes to be transferred; must be
     *         non-negative
     *
     * @return  The number of bytes, possibly zero,
     *          that were actually transferred
     *
     * @throws IllegalArgumentException
     *         If the preconditions on the parameters do not hold
     *
     * @throws  NonReadableChannelException
     *          If the source channel was not opened for reading
     *
     * @throws  NonWritableChannelException
     *          If this channel was not opened for writing
     *
     * @throws  ClosedChannelException
     *          If either this channel or the source channel is closed
     *
     * @throws  AsynchronousCloseException
     *          If another thread closes either channel
     *          while the transfer is in progress
     *
     * @throws  ClosedByInterruptException
     *          If another thread interrupts the current thread while the
     *          transfer is in progress, thereby closing both channels and
     *          setting the current thread's interrupt status
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract long transferFrom(ReadableByteChannel src,
                                      long position, long count)
        throws IOException;

    /**
     * 从给定的文件位置开始，从这个通道读取字节序列到给定的缓冲区。
     *
     * <p> 这个方法的工作方式与read(ByteBuffer)方法相同，不同的是字节是从给定的文件位置而不是通道的当前位置开始读取的。
     * 这个方法不改变这个通道的位置。如果给定的位置大于文件的当前大小，则不读取字节。</p>
     *
     * @param  dst
     *         The buffer into which bytes are to be transferred
     *
     * @param  position
     *         The file position at which the transfer is to begin;
     *         must be non-negative
     *
     * @return  The number of bytes read, possibly zero, or <tt>-1</tt> if the
     *          given position is greater than or equal to the file's current
     *          size
     *
     * @throws  IllegalArgumentException
     *          If the position is negative
     *
     * @throws  NonReadableChannelException
     *          If this channel was not opened for reading
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  AsynchronousCloseException
     *          If another thread closes this channel
     *          while the read operation is in progress
     *
     * @throws  ClosedByInterruptException
     *          If another thread interrupts the current thread
     *          while the read operation is in progress, thereby
     *          closing the channel and setting the current thread's
     *          interrupt status
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract int read(ByteBuffer dst, long position) throws IOException;

    /**
     * 从给定的文件位置开始，从给定的缓冲区向此通道写入字节序列。
     *
     * <p> 这个方法的工作方式与write(ByteBuffer)方法相同，
     * 不同的是字节是从给定的文件位置而不是通道的当前位置开始写入的。
     * 此方法不修改该通道的位置。
     * 如果给定的位置大于文件的当前大小，那么文件将被扩展以容纳新的字节;
     * 前一个文件结束字节和新写入字节之间的任何字节的值都是未指定的。 </p>
     *
     * @param  src
     *         The buffer from which bytes are to be transferred
     *
     * @param  position
     *         The file position at which the transfer is to begin;
     *         must be non-negative
     *
     * @return  The number of bytes written, possibly zero
     *
     * @throws  IllegalArgumentException
     *          If the position is negative
     *
     * @throws  NonWritableChannelException
     *          If this channel was not opened for writing
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  AsynchronousCloseException
     *          If another thread closes this channel
     *          while the write operation is in progress
     *
     * @throws  ClosedByInterruptException
     *          If another thread interrupts the current thread
     *          while the write operation is in progress, thereby
     *          closing the channel and setting the current thread's
     *          interrupt status
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract int write(ByteBuffer src, long position) throws IOException;


    // -- Memory-mapped buffers --

    /**
     * 用于文件映射模式的类型安全枚举。
     *
     * @since 1.4
     *
     * @see java.nio.channels.FileChannel#map
     */
    public static class MapMode {

        /**
         * 只读映射的模式。
         */
        public static final MapMode READ_ONLY
            = new MapMode("READ_ONLY");

        /**
         * 读/写映射的模式。
         */
        public static final MapMode READ_WRITE
            = new MapMode("READ_WRITE");

        /**
         * 私有(写时复制)映射的模式。
         */
        public static final MapMode PRIVATE
            = new MapMode("PRIVATE");

        private final String name;

        private MapMode(String name) {
            this.name = name;
        }

        /**
         * 返回描述此文件映射模式的字符串。
         *
         * @return  A descriptive string
         */
        public String toString() {
            return name;
        }

    }

    /**
     * 将此通道文件的一个区域直接映射到内存中。
     *
     * <p> 文件的一个区域可以在以下三种模式中被映射到内存:
     * </p>
     *
     * <ul>
     *
     *   <li><p>只读:任何修改缓存的尝试都会导致java.nio.ReadOnlyBufferException被抛出。</p></li>
     *
     *   <li><p> 读/写:对结果缓冲区所做的更改将最终传播到文件中;它们可能被其他映射了相同文件的程序访问，
     *   也可能不被访问。</p></li>
     *
     *   <li><p> Private:对结果缓冲区所做的更改将不会传播到该文件，其他程序不可见这些改变;
     *   相反，它们将导致创建缓冲区中修改过的部分的私有复制。</p></li>
     *
     * </ul>
     *
     * <p> 对于只读映射，此通道必须已打开以供读取;
     * 对于读/写或私有映射，此通道必须同时为读和写打开。
     *
     * <p> 这个方法返回的MappedByteBuffer将有一个0的位置和size的限制和容量;
     * 它的标记将是未定义的。
     * 缓冲区及其所代表的映射将保持有效，直到缓冲区本身被垃圾收集为止。
     *
     * <p> 映射一旦建立，就不依赖于用于创建它的文件通道。
     * 特别是，关闭通道对映射的有效性没有影响。
     *
     * <p> 内存映射文件的许多细节本质上依赖于底层操作系统，因此未指定。
     * 当请求的区域不完全包含在此通道的文件中时，此方法的行为是未指定的。
     * 这个程序或另一个程序对基础文件的内容或大小所做的更改是否传播到缓冲区是未指定的。
     * 将对缓冲区的更改传播到文件的速率未指定。
     *
     * <p> 对于大多数操作系统来说，将文件映射到内存要比通过通常的读写方法读写几十千字节的数据要昂贵得多。
     * 从性能的角度来看，通常只值得将相对较大的文件映射到内存中。</p>
     *
     * @param  mode
     *         One of the constants {@link MapMode#READ_ONLY READ_ONLY}, {@link
     *         MapMode#READ_WRITE READ_WRITE}, or {@link MapMode#PRIVATE
     *         PRIVATE} defined in the {@link MapMode} class, according to
     *         whether the file is to be mapped read-only, read/write, or
     *         privately (copy-on-write), respectively
     *
     * @param  position
     *         The position within the file at which the mapped region
     *         is to start; must be non-negative
     *
     * @param  size
     *         The size of the region to be mapped; must be non-negative and
     *         no greater than {@link java.lang.Integer#MAX_VALUE}
     *
     * @return  The mapped byte buffer
     *
     * @throws NonReadableChannelException
     *         If the <tt>mode</tt> is {@link MapMode#READ_ONLY READ_ONLY} but
     *         this channel was not opened for reading
     *
     * @throws NonWritableChannelException
     *         If the <tt>mode</tt> is {@link MapMode#READ_WRITE READ_WRITE} or
     *         {@link MapMode#PRIVATE PRIVATE} but this channel was not opened
     *         for both reading and writing
     *
     * @throws IllegalArgumentException
     *         If the preconditions on the parameters do not hold
     *
     * @throws IOException
     *         If some other I/O error occurs
     *
     * @see java.nio.channels.FileChannel.MapMode
     * @see java.nio.MappedByteBuffer
     */
    public abstract MappedByteBuffer map(MapMode mode,
                                         long position, long size)
        throws IOException;


    // -- Locks --

    /**
     * 获取此通道文件的给定区域上的锁。
     *
     * <p> 此方法的调用将阻塞，直到区域可以被锁定、此通道被关闭或调用线程被中断(以先发生的为准)。
     *
     * <p> 如果在调用此方法期间，另一个线程关闭此通道，则将抛出AsynchronousCloseException。
     *
     * <p> 如果调用线程在等待获取锁的过程中被中断，那么它的中断状态将被设置，并抛出FileLockInterruptionException。
     * 如果调用者的中断状态设置在这个方法被调用时，那么这个异常将立即被抛出;线程的中断状态不会被改变。
     *
     * <p> 由position和size参数指定的区域不需要包含在实际的底层文件中，甚至不需要重叠。
     * 锁定区域的大小固定;
     * 如果一个被锁定的区域最初包含文件的结尾，并且文件超出了该区域，那么该文件的新部分将不会被锁覆盖。
     * 如果预期一个文件的大小会增长，并且需要对整个文件加锁，那么应该锁定一个从0开始，且不小于预期文件最大大小的区域。
     * 零参数lock()方法只是锁定一个长度为Long.MAX_VALUE的区域。
     *
     * <p> 一些操作系统不支持共享锁，在这种情况下，对共享锁的请求会自动转换为对独占锁的请求。
     * 新获得的锁是共享的还是独占的，可以通过调用结果锁对象的isShared方法来测试。
     *
     * <p> 文件锁代表整个Java虚拟机。
     * 它们不适用于控制同一虚拟机中的多个线程对文件的访问。</p>
     *
     * @param  position
     *         The position at which the locked region is to start; must be
     *         non-negative
     *
     * @param  size
     *         The size of the locked region; must be non-negative, and the sum
     *         <tt>position</tt>&nbsp;+&nbsp;<tt>size</tt> must be non-negative
     *
     * @param  shared
     *         <tt>true</tt> to request a shared lock, in which case this
     *         channel must be open for reading (and possibly writing);
     *         <tt>false</tt> to request an exclusive lock, in which case this
     *         channel must be open for writing (and possibly reading)
     *
     * @return  A lock object representing the newly-acquired lock
     *
     * @throws  IllegalArgumentException
     *          If the preconditions on the parameters do not hold
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  AsynchronousCloseException
     *          If another thread closes this channel while the invoking
     *          thread is blocked in this method
     *
     * @throws  FileLockInterruptionException
     *          If the invoking thread is interrupted while blocked in this
     *          method
     *
     * @throws  OverlappingFileLockException
     *          If a lock that overlaps the requested region is already held by
     *          this Java virtual machine, or if another thread is already
     *          blocked in this method and is attempting to lock an overlapping
     *          region
     *
     * @throws  NonReadableChannelException
     *          If <tt>shared</tt> is <tt>true</tt> this channel was not
     *          opened for reading
     *
     * @throws  NonWritableChannelException
     *          If <tt>shared</tt> is <tt>false</tt> but this channel was not
     *          opened for writing
     *
     * @throws  IOException
     *          If some other I/O error occurs
     *
     * @see     #lock()
     * @see     #tryLock()
     * @see     #tryLock(long,long,boolean)
     */
    public abstract FileLock lock(long position, long size, boolean shared)
        throws IOException;

    /**
     * 获取此通道文件的排他锁。
     *
     * <p> 以fc.lock()形式调用这个方法的行为与调用的方式完全相同
     *
     * <pre>
     *     fc.{@link #lock(long,long,boolean) lock}(0L, Long.MAX_VALUE, false) </pre>
     *
     * @return  A lock object representing the newly-acquired lock
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  AsynchronousCloseException
     *          If another thread closes this channel while the invoking
     *          thread is blocked in this method
     *
     * @throws  FileLockInterruptionException
     *          If the invoking thread is interrupted while blocked in this
     *          method
     *
     * @throws  OverlappingFileLockException
     *          If a lock that overlaps the requested region is already held by
     *          this Java virtual machine, or if another thread is already
     *          blocked in this method and is attempting to lock an overlapping
     *          region of the same file
     *
     * @throws  NonWritableChannelException
     *          If this channel was not opened for writing
     *
     * @throws  IOException
     *          If some other I/O error occurs
     *
     * @see     #lock(long,long,boolean)
     * @see     #tryLock()
     * @see     #tryLock(long,long,boolean)
     */
    public final FileLock lock() throws IOException {
        return lock(0L, Long.MAX_VALUE, false);
    }

    /**
     * 试图获取此通道文件的给定区域上的锁。
     *
     * <p> 这个方法不会阻塞。调用总是立即返回，要么获得了请求区域上的锁，要么失败了。
     * 如果它因为另一个程序持有重叠的锁而无法获取锁，那么它将返回null。
     * 如果它因为任何其他原因而无法获得锁，则抛出一个适当的异常。
     *
     * <p> 由position和size参数指定的区域不需要包含在实际的底层文件中，甚至不需要重叠。
     * 锁定区域的大小固定;如果一个被锁定的区域最初包含文件的结尾，并且文件超出了该区域，那么该文件的新部分将不会被锁覆盖。
     * 如果预期一个文件的大小会增长，并且需要对整个文件加锁，那么应该锁定一个从0开始，且不小于预期文件最大大小的区域。
     * 零参数tryLock()方法只是锁定一个长度为Long.MAX_VALUE的区域。
     *
     * <p> 一些操作系统不支持共享锁，在这种情况下，对共享锁的请求会自动转换为对独占锁的请求。
     * 新获得的锁是共享的还是独占的，可以通过调用结果锁对象的isShared方法来测试。
     *
     * <p> 文件锁代表整个Java虚拟机。
     * 它们不适用于控制同一虚拟机中的多个线程对文件的访问。</p>
     *
     * @param  position
     *         The position at which the locked region is to start; must be
     *         non-negative
     *
     * @param  size
     *         The size of the locked region; must be non-negative, and the sum
     *         <tt>position</tt>&nbsp;+&nbsp;<tt>size</tt> must be non-negative
     *
     * @param  shared
     *         <tt>true</tt> to request a shared lock,
     *         <tt>false</tt> to request an exclusive lock
     *
     * @return  A lock object representing the newly-acquired lock,
     *          or <tt>null</tt> if the lock could not be acquired
     *          because another program holds an overlapping lock
     *
     * @throws  IllegalArgumentException
     *          If the preconditions on the parameters do not hold
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  OverlappingFileLockException
     *          If a lock that overlaps the requested region is already held by
     *          this Java virtual machine, or if another thread is already
     *          blocked in this method and is attempting to lock an overlapping
     *          region of the same file
     *
     * @throws  IOException
     *          If some other I/O error occurs
     *
     * @see     #lock()
     * @see     #lock(long,long,boolean)
     * @see     #tryLock()
     */
    public abstract FileLock tryLock(long position, long size, boolean shared)
        throws IOException;

    /**
     * 试图获取此通道文件的独占锁。
     *
     * <p> 调用fc.tryLock()形式的这个方法的行为与调用的方式完全相同
     *
     * <pre>
     *     fc.{@link #tryLock(long,long,boolean) tryLock}(0L, Long.MAX_VALUE, false) </pre>
     *
     * @return  A lock object representing the newly-acquired lock,
     *          or <tt>null</tt> if the lock could not be acquired
     *          because another program holds an overlapping lock
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  OverlappingFileLockException
     *          If a lock that overlaps the requested region is already held by
     *          this Java virtual machine, or if another thread is already
     *          blocked in this method and is attempting to lock an overlapping
     *          region
     *
     * @throws  IOException
     *          If some other I/O error occurs
     *
     * @see     #lock()
     * @see     #lock(long,long,boolean)
     * @see     #tryLock(long,long,boolean)
     */
    public final FileLock tryLock() throws IOException {
        return tryLock(0L, Long.MAX_VALUE, false);
    }

}
